﻿using System;
using System.Text;
using System.IO;
using System.Collections;

using Ionic.Zip;

namespace McMySkin_Installer
{
    //安装类型
    public enum InstallTpye
    {
        INSTALL_MMS,
        INSTALL_MOJANG,
        INSTALL_SM
    }

    public class Installer
    {
        //皮肤编码地址
        public const string ENCODE_URL = "http://www.mcmyskin.com/api/encode.php?uid={0}&type={1}&hd={2}";

        //链接地址16进制数据
        public const string SKIN_URL_MOJANG_OLD = "27687474703A2F2F73332E616D617A6F6E6177732E636F6D2F4D696E656372616674536B696E732F";
        public const string SKIN_URL_MOJANG_NEW = "2A687474703A2F2F736B696E732E6D696E6563726166742E6E65742F4D696E656372616674536B696E732F";
        public const string SKIN_URL_MMS_OLD = "23687474703A2F2F6D636D79736B696E2E636F6D2F736B696E732E7068703F6E616D653D";
        public const string SKIN_URL_SM = "2B687474703A2F2F736D2E736B696E6D652E636F2F6765742E7068703F747970653D736B696E2666696C653D";
        public const string CLOAK_URL_MOJANG_OLD = "28687474703A2F2F73332E616D617A6F6E6177732E636F6D2F4D696E656372616674436C6F616B732F";
        public const string CLOAK_URL_MOJANG_NEW = "2B687474703A2F2F736B696E732E6D696E6563726166742E6E65742F4D696E656372616674436C6F616B732F";
        public const string CLOAK_URL_MMS_OLD = "28687474703A2F2F6D636D79736B696E2E636F6D2F736B696E732E7068703F63617065266E616D653D";
        public const string CLOAK_URL_SM = "2C687474703A2F2F736D2E736B696E6D652E636F2F6765742E7068703F747970653D636C6F616B2666696C653D";

        public const string SKIN_URL = "33687474703A2F2F736B696E732E6D636D79736B696E2E636F6D2F2D34642D34342D37332D37372D34662D37612D34312D33642B";
        public const string CLOAK_URL = "33687474703A2F2F736B696E732E6D636D79736B696E2E636F6D2F2D34642D34342D37332D37382D34662D37612D34312D33642B";

        //待替换数据数组
        public string[] SKINS = {SKIN_URL_MOJANG_OLD,SKIN_URL_MOJANG_NEW,SKIN_URL_MMS_OLD,SKIN_URL_SM };
        public string[] CLOAKS = { CLOAK_URL_MOJANG_OLD, CLOAK_URL_MOJANG_NEW, CLOAK_URL_MMS_OLD, CLOAK_URL_SM };

        private string Filename;
        private InstallTpye Type;

        //安装进度
        public float Progress = 0;
        //安装是否完成
        public bool done = false;

        /// <summary>
        /// MMS安装器
        /// </summary>
        /// <param name="filename">文件位置</param>
        /// <param name="type">安装方式</param>
        public Installer(string filename, InstallTpye type)
        {
            this.Filename = filename;
            this.Type = type;
        }

        /// <summary>
        /// 正式开始安装
        /// </summary>
        public void Run()
        {
            //确认安装方式
            string skin_url;
            string cloak_url;

            //判断是否匿名安装
            if (Config.UseServerUrl)
            {
                string skinEncode = "http://skins.mcmyskin.com/" + Unit.ReadURL(ENCODE_URL.Replace("{0}", LoginStatus.Uid).Replace("{1}", "0").Replace("{2}", "1"),null,Encoding.UTF8) + "+";
                string cloakEncode = "http://skins.mcmyskin.com/" + Unit.ReadURL(ENCODE_URL.Replace("{0}", LoginStatus.Uid).Replace("{1}", "1").Replace("{2}", "1"), null, Encoding.UTF8) + "+";
                //转换url为16进制
                skin_url = ConvertUrl(skinEncode);
                cloak_url = ConvertUrl(cloakEncode);
            }
            //检查安装类型
            else
            {
                if (Type == InstallTpye.INSTALL_MMS)
                {
                    skin_url = SKIN_URL;
                    cloak_url = CLOAK_URL;
                }
                else if (Type == InstallTpye.INSTALL_MOJANG)
                {
                    skin_url = SKIN_URL_MOJANG_NEW;
                    cloak_url = CLOAK_URL_MOJANG_NEW;
                }
                else if (Type == InstallTpye.INSTALL_SM)
                {
                    skin_url = SKIN_URL_SM;
                    cloak_url = CLOAK_URL_SM;
                }
                else
                {
                    skin_url = SKIN_URL;
                    cloak_url = CLOAK_URL;
                }
            }

            //安装
                //table 为替换文件列表
                Hashtable table = new Hashtable();

                ZipFile zip = ZipFile.Read(Filename);

                //进度计算变量
                int fileNumber = zip.Count;
                int doneFile = 0;

                //开始遍历压缩包内文件
                foreach (ZipEntry e in zip)
                {
                    Stream s = e.OpenReader();
                    if (Config.debug)
                        Console.WriteLine("Extracting " + e.FileName);

                    //以stream方式读取文件
                    BufferedStream bs = new BufferedStream(s);
                    byte[] fileBytes = new byte[bs.Length];
                    bs.Read(fileBytes, 0, (int)bs.Length);
                    bs.Flush();
                    bs.Close();

                    s.Close();

                    //装换二进制为16进制
                    string fileString = this.BytesToHex(fileBytes);

                    //进度
                    doneFile++;

                    //确认是否发现需要替换的文件
                    bool found = false;

                    //遍历待替换列表
                    foreach (string str in SKINS)
                    {
                        if (fileString.Contains(str))
                        {
                            fileString = fileString.Replace(str, skin_url);

                            found = true;
                        }
                    }

                    foreach (string str2 in CLOAKS)
                    {
                        if (fileString.Contains(str2))
                        {
                            fileString = fileString.Replace(str2, cloak_url);

                            found = true;
                        }
                    }

                    //如果发现需要替换的文件，加入替换列表
                    if (found)
                    {
                        byte[] newFileBytes = this.HexToBytes(fileString);
                        table.Add(e.FileName, newFileBytes);
                    }

                    //计算安装进度
                    Progress = (float)doneFile / (float)fileNumber;
                }

                //由于使用 foreach，所以无法在遍历时替换，所以转移到外部替换。
                foreach (string s in table.Keys)
                {
                    if (Config.debug) Console.WriteLine("Patching: " + s);
                    byte[] bs = (byte[])table[s];
                    zip.UpdateEntry(s, bs);
                }


                //保存压缩包，以创建临时文件的方法进行，避免文件被zip流冲突
                FileStream fs = new FileStream(Filename + ".new", FileMode.Create);
                zip.Save(fs);

                //销毁，关闭操作流
                fs.Close();
                zip.Dispose();

                //删除临时文件
                File.Delete(Filename);
                File.Move(Filename + ".new", Filename);

                //安装完成
                done = true;
        }

        private string ConvertUrl(string str)
        {
            return str.Length.ToString("X") + Unit.ConvertToHex(str);
        }

        private string BytesToHex(byte[] bytes)
        {
            string hexString = string.Empty;
            if (bytes != null)
            {
                StringBuilder strB = new StringBuilder();

                for (int i = 0; i < bytes.Length; i++)
                {
                    strB.Append(bytes[i].ToString("X2"));
                }
                hexString = strB.ToString();
            }
            return hexString;
        }

        private byte[] HexToBytes(string hexString)
        {
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            return returnBytes;
        }
    }
}
